//
//  JKNetworkManager.swift
//  新浪微博
//
//  Created by Jack.Lin on 16/7/2.
//  Copyright © 2016年 Jack.Lin. All rights reserved.
//

import UIKit
import AFNetworking

enum JKHTTPMethod {
    case GET
    case POST
}

class JKNetworkManager: AFHTTPSessionManager {

    // 创建单例
    // 在第一次访问时, 执行闭包, 并且将结果保存在 shared 常量中
//    static let shared = JKNetworkManager()
    
    static let shared: JKNetworkManager = {
     
        let instance = JKNetworkManager()
     
        // 设置响应反序列化支持的数据类型
        instance.responseSerializer.acceptableContentTypes?.insert("text/plain")
        
        return instance
        }()
    
    
    // 访问令牌, 所有的网络请求, 都是基于此令牌(登录除外)
    // token 是有时限的, 默认用户是三天
    // 模拟 token 过期 -> 服务器返回的状态码是 403
//    var accessToken: String? //= "2.00AREEODs8MrbE0d11f247ecNCdneB"
//    
//    var uid: String? = "12341234"

    // 用户账户的懒加载属性
    lazy var userAccount = JKUserAccount()
    
    var userLogon: Bool {
       
//        return accessToken != nil
        return userAccount.access_token != nil
    }
    
    
    // 专门负责接拼 token 的网络请求方法
    /// - parameter method:     GET / POST
    /// - parameter URLString:  URLString
    /// - parameter parameters: 参数字典
    /// - parameter name:       上传文件使用的字段名，默认为 nil，不上传文件
    /// - parameter data:       上传文件的二进制数据，默认为 nil，不上传文件
    /// - parameter completion: 完成回调

    func tokenRequest(method: JKHTTPMethod = .GET, URLString: String, parameters: [String: AnyObject]?, name: String? = nil, data: Data? = nil, completion: (json: AnyObject?, isSuccess: Bool)->()) {
    
        // 处理 token 字典
        guard let token = userAccount.access_token else {
            print("没有 token! 需要登录")
            
            NotificationCenter.default.post(name: NSNotification.Name(rawValue: JKUserShouldLoginNotification), object: "bad token")
            
            completion(json: nil, isSuccess: false)
            
            return
        }
        
        var parameters = parameters
        if parameters == nil {
           
            parameters = [String :AnyObject]()
            
        }
        parameters!["access_token"] = token
        // 3> 判断 name 和 data
        if let name = name, data = data {
            // 上传文件
            upload(URLString: URLString, parameters: parameters, name: name, data: data, completion: completion)
        } else {
            
            // 调用 request 发起真正的网络请求方法
            // request(URLString: URLString, parameters: parameters, completion: completion)
            request(method: method, URLString: URLString, parameters: parameters!, completion: completion)
        }

    }
    
    
    // 上传文件必须是 POST 方法, GET 只能获取数据
    // 封装 AFN 的上传文件方法
    func upload(URLString: String, parameters: [String: AnyObject]?, name: String, data: Data, completion: (json: AnyObject?, isSuccess: Bool)->()) {
        
        post(URLString, parameters: parameters, constructingBodyWith: { (formData) in
            
            // 创建 formData
            /**
             1. data: 要上传的二进制数据
             2. name: 服务器接收数据的字段名
             3. fileName: 保存在服务器的文件名，大多数服务器，现在可以乱写
             很多服务器，上传图片完成后，会生成缩略图，中图，大图...
             4. mimeType: 告诉服务器上传文件的类型，如果不想告诉，可以使用 application/octet-stream
             image/png image/jpg image/gif
             */
            
            formData.appendPart(withFileData: data, name: name, fileName: "xxx", mimeType: "application/octet-stream")
            
            }, progress: nil, success: { (_, json) in
                
                completion(json: json, isSuccess: true)
        }) { (task, error) in
            
            if (task?.response as? HTTPURLResponse)?.statusCode == 403 {
                print("Token 过期了")
                
                // 发送通知，提示用户再次登录(本方法不知道被谁调用，谁接收到通知，谁处理！)
                NotificationCenter.default.post(
                    name: NSNotification.Name(rawValue: JKUserShouldLoginNotification),
                    object: "bad token")
            }
            
            print("网络请求错误 \(error)")
            
            completion(json: nil, isSuccess: false)
        }
    }
    
    
    
    
    
    
    
    
    /// 封装的 AFN 的 GET / POST 请求
    func request(method: JKHTTPMethod = .GET, URLString: String, parameters: [String: AnyObject], completion: (json: AnyObject?, isSuccess: Bool)->()) {
        
        let success = { (task: URLSessionDataTask, json: AnyObject?)->() in
            completion(json: json, isSuccess: true)
        }
    // Cannot convert value of type '(URLSessionDataTask, NSError) -> ()' to expected argument type '((URLSessionDataTask?, NSError) -> Void)?'
    // 因为失败的话,可能是token过期或者传递的是nil,所以failure的网络请求任务需要加?
        let failure = { (task: URLSessionDataTask?, error: NSError)->() in
          
            if (task?.response as? HTTPURLResponse)?.statusCode == 403 {
                
                print("Token 过期了")
            }
            
            print("网络请求错误 \(error)")
            
            completion(json: nil, isSuccess: false)
        }
        if method == .GET {
            get(URLString, parameters: parameters, progress: nil, success: success, failure: failure)
        } else {
            post(URLString, parameters: parameters, progress: nil, success: success, failure: failure)
        }
    }
    
}
